use Win32;

my $uidstore = shift @ARGV;
my $basedir = shift @ARGV;
my $subdir = shift @ARGV;
my $idprefix = shift @ARGV;
my $outfile = shift @ARGV;
my $excdir = shift @ARGV;
my $excfile = shift @ARGV;
my $inconlyfile = shift @ARGV;
my $seq = 1;
die "Usage: builddir.pl <uidstore> <basedir> <subdir> <idprefix> <outfile> [<exclude subdir>] [<exclude files>] [<include only files>]\n\n" unless ($uidstore && $basedir && $subdir && $idprefix && $outfile);

$excdir =~ s/%/|/g;
$excfile =~ s/%/|/g;
$inconlyfile =~ s/%/|/g;

LoadGuidStore();

open(OUT, ">$outfile") || die "Could not open output file ($outfile)!\n";
print OUT "<Include>\n";
ProcessSubDir($subdir);
print OUT "</Include>\n";
close(OUT);

SaveGuidStore();


sub ProcessSubDir {
  my $subdir = shift;
  my $lastdir;

  $subdir =~ s/\\$//;

  $subdir =~ /\\([^\\]*)$/;
  $lastdir = $1;
  $lastdir = $subdir if ($lastdir eq "");
  $idname = $subdir;
  $idname =~ s/\\/_/g;
  $idname =~ s/\-/_/g;

  return if ($lastdir =~ /^$excdir$/);

  print OUT "<Directory Id=\"$idprefix\_$idname\" Name=\"$lastdir\">\n";
  print OUT " <Component Id=\"$idprefix\_$idname\" Guid=\"" . GetGuid("$idprefix\_$idname") . "\">\n";
  opendir(DIR, "$basedir\\$subdir") || die "Failed in opendir of $basedir\\$subdir\n";
  foreach my $entry (readdir(DIR)) {
    my $fid = $idprefix . "_" . $seq;
    next unless (-f "$basedir\\$subdir\\$entry");
    next if ($entry =~ /^$excfile$/);
    next if ($inconlyfile && !($entry =~ /^$inconlyfile$/));
    
    # Get a shortname for all files. Some of the sets we have are pretty
    # large and WiX can generate conflicting names
    my $shortname = Win32::GetShortPathName("$basedir\\$subdir\\$entry");
    $shortname =~ /\\([^\\]*)$/;
    $shortname = $1;
    $shortstr = ($shortname eq $entry)?"":" ShortName=\"F$seq\"";

    print OUT "  <File Id=\"$fid\" Name=\"$entry\"$shortstr DiskId=\"1\" Source=\"$basedir/$subdir/$entry\" />\n";

    $seq++;
  }
  closedir(DIR);

  print OUT " </Component>\n";
  opendir(DIR, "$basedir\\$subdir") || die "Failed in opendir\n";
  foreach my $entry (readdir(DIR)) {
    next unless (-d "$basedir\\$subdir\\$entry");
    next if ($entry =~ /^[\.]+$/);
    ProcessSubDir("$subdir\\$entry");
  }
  closedir(DIR);
  ####
  print OUT "</Directory>\n";

}

my %uids;

sub LoadGuidStore {
  open(UIS, "$uidstore") || die "Could not open uid store: $uidstore\n";
  while (<UIS>) {
    chomp;
    my ($id, $uid) = split /;/;
    $uids{$id} = $uid;
  }
  close(UIS);
}

sub GetGuid {
  my $id = shift;

  $uid = $uids{$id};
  return $uid if ($uid);

  $uid = MakeGuid();
  $uids{$id} = $uid;
  return $uid;
}

sub SaveGuidStore {
  open(UIS, ">$uidstore") || die "Could not write to uid store: $uidstore\n";
  foreach my $id (sort keys %uids) {
    print UIS "$id;$uids{$id}\n";
  }
  close(UIS);
}


sub MakeGuid {
  my $u = Win32::GuidGen();
  $u =~ s/[{}]//g;
  return $u;
}
